﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using MiniExcelLibs;
using NLog;
using QModels;
using QServices.QJobs;
using QServices.Services;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using Quartz;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Quartz.Impl;
using static Quartz.Logging.OperationName;
using MQTTnet.Client;



namespace QServices
{
    public static class AppRuntime
    {
        public static bool IsUpdateUpdateCarStatus { get; set; }
        public static bool IsUpdateCarElectricLimit { get; set; }
        public static bool IsUpdateChongDianTask { get; set; }

        public static bool IsUpdatePigeonCage { get; set; }
        public static bool IsUpdateDosingSchedule { get; set; }


		public static int ChongDianHour { get; set; } = 2;
        public static int ChongDianMinute { get; set; } = 0;


		public static string? Rabbitmq_ip {  get; set; }
		public static int? Rabbitmq_port { get; set; }
		public static string? Rabbitmq_user { get; set; }
		public static string? Rabbitmq_pwd { get; set; }

        public static HashSet<string> FirstFeedCache { get; set; } = new HashSet<string>();
		public static HashSet<string> SecondFeedCache { get; set; } = new HashSet<string>();
		public static HashSet<string> ThirdFeedCache { get; set; } = new HashSet<string>();


		public static bool IsDebug { get; set; } = false;
        public static Lazy<NLog.Logger> Logger = new Lazy<NLog.Logger>(() =>
        {
            var logger = NLog.LogManager.GetCurrentClassLogger();
            return logger;
        });


        public static void Init()
        {
			InitService();
			InitCarNumber();
		
            InitFeedRate();
            
            InitQu();
        }


        public static string Alarm {  get; set; }
        public static decimal BigPigeon { get; set; }
        public static List<decimal> SmallPigeon { set; get; } = new List<decimal>();
        public static List<string> Areas { get; set; } = new List<string>();

        public static string DbConnectionString { get; set; }
        public static string MysqlDbConnectionString {  get; set; }
        public static string MysqlVersionStr {  get; set; }
        private static IServiceProvider Services { get; set; }
        public static bool IsLogger { get; set; }=true;
        public static decimal MaxTemperature {  get; set; }
        public static decimal MinTemperature {  set; get; }

        public static AgvCar AgvCar { get; set; }


        public static Lazy<Dictionary<string, ModBusTcpAddress>> ModBusAddresses_Reader = new Lazy<Dictionary<string, ModBusTcpAddress>>(() =>
        {
            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plcAddress","plc.xlsx");
            var dic = GetModBusTcpAddressFromCSV(path,"reader");
            return dic;
        },true);
        public static Lazy<Dictionary<string, ModBusTcpAddress>> ModBusAddresses_Writer = new Lazy<Dictionary<string, ModBusTcpAddress>>(() =>
        {

            var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "plcAddress", "plc.xlsx");
            var dic = GetModBusTcpAddressFromCSV(path, "writer");
            return dic;


        }, true);

        private static Dictionary<string, ModBusTcpAddress> GetModBusTcpAddressFromCSV(string path,string sheet)
        {
            var dic = new Dictionary<string, ModBusTcpAddress>();
            if (!File.Exists(path)) return dic;
            var lst = MiniExcel.Query<ModBusTcpAddress>(path,sheet);
            foreach(var item in lst)
            {
                if(!dic.ContainsKey(item.name)) dic.Add(item.name,item);
            }
            return dic;
        }


		public static IMqttClient? m_mqttclient { get; set; } = null;
		public static StdSchedulerFactory SchedulerFactory { get; set; }
        public static IScheduler Scheduler { get; set; }
		public static IServiceProvider GetService()
        {
            if (Services == null) InitService();
            if (string.IsNullOrWhiteSpace(CarNumber)) InitCarNumber();
            //if (SmallPigeon == null || SmallPigeon.Count <= 0) InitFeedRate();

            return Services;
        }

        public static   void InitQu()
        {
            var car = GetService().GetService<AgvCarService>().GetAgvCarByNumber(AppRuntime.CarNumber);
            AgvCar = car;
            IJobDetail carEleJson = JobBuilder.Create<CarElectricJob>().WithIdentity("CarElectricJob", "AGV").Build();
            ITrigger carTrigger = TriggerBuilder.Create().WithIdentity("CarElectricJobTrigger", "AGV")
                .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(car.TaskHour,car.TaskMinute))
            .Build();

			IJobDetail secondJob = JobBuilder.Create<SecondJob>().WithIdentity("SecondJob", "SecondJob").Build();
			ITrigger secondTrigger = TriggerBuilder.Create().WithIdentity("SecondTrigger", "SecondJob")
                .WithSimpleSchedule(x =>
                {
                    
                    x.WithIntervalInSeconds(1).RepeatForever();
                })
			.Build();

			IJobDetail second30Job = JobBuilder.Create<Second30Job>().WithIdentity("Second30Job", "Second30Job").Build();
			ITrigger second30Trigger = TriggerBuilder.Create().WithIdentity("Second30Trigger", "Second30Job")
				.WithSimpleSchedule(x =>
				{

					x.WithIntervalInSeconds(30).RepeatForever();
				})
			.Build();

			IJobDetail minuteJob = JobBuilder.Create<MinuteJob>().WithIdentity("MinuteJob", "MinuteJob").Build();
			ITrigger minuteTrigger = TriggerBuilder.Create().WithIdentity("MinuteTrigger", "MinuteJob")
				.WithSimpleSchedule(x =>
				{
					x.WithIntervalInMinutes(1).RepeatForever();
				})
			.Build();
			IJobDetail minute5Job = JobBuilder.Create<MinuteFiveJob>().WithIdentity("Minute5Job", "Minute5Job").Build();
			ITrigger minute5Trigger = TriggerBuilder.Create().WithIdentity("Minute5Trigger", "Minute5Job")
				.WithSimpleSchedule(x =>
				{
					x.WithIntervalInMinutes(5).RepeatForever();
				})
			.Build();
			IJobDetail minute10Job = JobBuilder.Create<MinuteTenJob>().WithIdentity("Minute10Job", "Minute10Job").Build();
			ITrigger minute10Trigger = TriggerBuilder.Create().WithIdentity("Minute10Trigger", "Minute10Job")
				.WithSimpleSchedule(x =>
				{
					x.WithIntervalInMinutes(10).RepeatForever();
				})
			.Build();

            IJobDetail zerojob = JobBuilder.Create<ZeroJob>().WithIdentity("Zero", "Zero").Build();
            ITrigger zerotrigger = TriggerBuilder.Create().WithIdentity("Zero","Zero")
                .WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(0,1))
                .Build();


            SchedulerFactory = new StdSchedulerFactory();
			//创建任务调度器
			IScheduler scheduler = SchedulerFactory.GetScheduler().GetAwaiter().GetResult();
           

            if (scheduler.IsStarted)
            {
                // 如果调度器正在运行，则关闭它
                scheduler.Shutdown(true);
            }
            // 清除任何可能存在的旧作业（仅在必要时）
            scheduler.Clear();
            //启动任务调度器
            scheduler.Start();

			//将创建的任务和触发器条件添加到创建的任务调度器当中
            scheduler.ScheduleJob(carEleJson,carTrigger);
            scheduler.ScheduleJob(secondJob, secondTrigger);
            scheduler.ScheduleJob(second30Job, second30Trigger);
            scheduler.ScheduleJob(minuteJob, minuteTrigger);
            scheduler.ScheduleJob(minute5Job, minute5Trigger);
            scheduler.ScheduleJob(minute10Job, minute10Trigger);
            scheduler.ScheduleJob(zerojob,zerotrigger);

            Scheduler = scheduler;

		}
        public static string CarNumber { get; set; }


        public static TodayDosingSchedule TodayDosingSchedule { get; set; }
        private static DosingSchedule DosingSchedule { get; set; }
        public static DosingSchedule GetDosingSchedule()
        {
            if (DosingSchedule == null)
            {
                var car = AppRuntime.GetService().GetService<AgvCarService>().GetAgvCarByNumber(AppRuntime.CarNumber);
                var schedule = AppRuntime.GetService().GetService<DosingScheduleService>().GetDosingScheduleByCarId(car.ID);
                DosingSchedule = schedule;
            }
            return DosingSchedule;
        }
        public static DosingSchedule GetDosingScheduleAndUpdate()
        {
            var car = AppRuntime.GetService().GetService<AgvCarService>().GetAgvCarByNumber(AppRuntime.CarNumber);
            var schedule = AppRuntime.GetService().GetService<DosingScheduleService>().GetDosingScheduleByCarId(car.ID);
            KKSchedule.Clear();
            KKSchedule.Add(0, new int[] { 0, 0, 0 });
            KKSchedule.Add(80, new int[] { schedule.First_80, schedule.Second_80, schedule.Third_80 });
            KKSchedule.Add(120, new int[] { schedule.First_120, schedule.Second_120, schedule.Third_120 });
            KKSchedule.Add(160, new int[] { schedule.First_160, schedule.Second_160, schedule.Third_160 });
            KKSchedule.Add(200, new int[] { schedule.First_200, schedule.Second_200, schedule.Third_200 });
            DosingSchedule = schedule;
            return DosingSchedule;
        }






        /// <summary>
        /// 初始化喂料量
        /// </summary>
        public static void InitFeedRate()
        {
            var agvCar = AppRuntime.GetService().GetService<AgvCarService>().GetAgvCarByNumber(AppRuntime.CarNumber);
            BigPigeon = agvCar.BigPigeon.Value;
            var smallPigeonStr =agvCar.SmallPigeon;
           
            smallPigeonStr.Split(',').ToList().ForEach(x =>
            {
                decimal.TryParse(x, out var y);
                SmallPigeon.Add(y);
            });

            var areastr = agvCar.Region;
            areastr.Split(',').ToList().ForEach(x =>
            {
                Areas.Add(x);
            });




        }
        private static void InitCarNumber()
        {
            var carNUmber = ConfigurationManager.AppSettings.Get("CarNumber");
            CarNumber = carNUmber ?? "1";
            var isloggerStr = ConfigurationManager.AppSettings.Get("IsLogger");
            bool.TryParse(isloggerStr, out var islogger);
            IsLogger=islogger;
            var alarm = ConfigurationManager.AppSettings.Get("Alarm");
            Alarm = alarm;
            var maxTemperature= ConfigurationManager.AppSettings.Get("MaxTemperature");
			var minTemperature = ConfigurationManager.AppSettings.Get("MinTemperature");
            decimal.TryParse(minTemperature, out var minTemp);
            decimal.TryParse(maxTemperature, out var maxTemp);
            MaxTemperature = maxTemp;
            MinTemperature = minTemp;

            var rabbitmq_ip = ConfigurationManager.AppSettings.Get("rabbitmq_ip");
            var rabbitmq_port= ConfigurationManager.AppSettings.Get("rabbitmq_port");
			var rabbitmq_user = ConfigurationManager.AppSettings.Get("rabbitmq_user");
			var rabbitmq_pwd = ConfigurationManager.AppSettings.Get("rabbitmq_pwd");

            Rabbitmq_ip = rabbitmq_ip;
            if(!string.IsNullOrWhiteSpace(rabbitmq_port))Rabbitmq_port=int.Parse(rabbitmq_port);
            Rabbitmq_user = rabbitmq_user;
            Rabbitmq_pwd = rabbitmq_pwd;

           

		}


        private static void InitService()
        {

            var services = new ServiceCollection();
            services.AddTransient<UserService>();
            services.AddTransient<DosingScheduleService>();
            services.AddTransient<AgvCarService>();
            services.AddTransient<PigeonCageService>();
            services.AddTransient<PigeonChildService>();
            services.AddTransient<PigeonEggService>();
            services.AddTransient<DailyPatrolInspectionService>();
            services.AddTransient<QTimerStatusService>();
            services.AddTransient<DeviceManagerService>();
            services.AddTransient<ParameterSettingService>();
            services.AddTransient<LsdService>();
            

            Services = services.BuildServiceProvider();

             
        }


        public static QPlcManager PlcManager { get; set; } = new QPlcManager();
        public static QPlcManager GetPlcManager()
        {
            if (PlcManager == null) PlcManager = new QPlcManager();
            return PlcManager;
        }

        public static Dictionary<int, int[]> KKSchedule = new Dictionary<int, int[]>();


        public static HashSet<string> PLCCache { get; set; } = new HashSet<string>();
        public static (bool IsOK, string PigeonCageId, string err) InteractionPLC(bool IsFirst, bool IsSecond, bool IsThird)
        {
            var pigeonCageId = string.Empty;
            try
            {
                pigeonCageId = GetPlcManager().GetBarCode();//"00e1f804-d5c7-4929-9206-cf5eabac3146";

                if (string.IsNullOrWhiteSpace(pigeonCageId)) return (false, pigeonCageId, "");
                if (PLCCache.Contains(pigeonCageId))
                {
                    return (false, pigeonCageId, "");
                }
                if (TodayDosingSchedule.CagesRelations.ContainsKey(pigeonCageId))
                {
                    var keyval = TodayDosingSchedule.CagesRelations[pigeonCageId];
                    var res = TodayDosingSchedule.CagesFeeds[keyval];
                    var newres = new int[res.Length];
                    for (int i = 0; i < res.Length; i++) newres[i] = res[i];
                    GetFeedSceduleRate(ref newres, IsFirst, IsSecond, IsThird);
                    GetPlcManager().上位机喂料量下达(newres);
                    var msg = $"--------{pigeonCageId}____{keyval}_____[{string.Join(",", newres)}]";
                    Logger_Info(msg);
                }
                PLCCache.Add(pigeonCageId);
                return (true, pigeonCageId, "");
            }
            catch (Exception ex)
            {
                Logger_Error(ex);
                return (false, pigeonCageId, ex.Message);
            }

        }
        private static void GetFeedSceduleRate(ref int[] values, bool IsFirst, bool IsSecond, bool IsThird)
        {
            if (values == null || values.Length == 0) return;
            for (int i = 0; i < values.Length; i++)
            {
                if (IsFirst) values[i] = KKSchedule[values[i]][0];
                else if (IsSecond) values[i] = KKSchedule[values[i]][1];
                else if (IsThird) values[i] = KKSchedule[values[i]][2];
            }
        }

        public static string[]GetBarCodeFromCurrentbarCode(string barcode)
        {
            var values = new string[8];
			var pigeonCageId = barcode;
			if (string.IsNullOrWhiteSpace(pigeonCageId)) return values;
			var building = pigeonCageId[0];
			var arrange = pigeonCageId.Substring(1, 2);
			var group = pigeonCageId.Substring(3, 3);
			int.TryParse(arrange, out int arrangeInt);
			var isOdd = arrangeInt % 2 != 0;
			if (arrangeInt % 2 == 0) arrangeInt -= 1;
			var tt = pigeonCageId.ToArray();

            for(int i = 1; i <= 4; i++)
            {
				var number = i.ToString("D2");
				tt[6] = number[0];
				tt[7] = number[1];
				var firstLine = arrangeInt.ToString("D2");
				tt[1] = firstLine[0];
				tt[2] = firstLine[1];
				var id_0 = string.Join("", tt);

				var secondLine = (arrangeInt + 1).ToString("D2");
				tt[1] = secondLine[0];
				tt[2] = secondLine[1];
				var id_1 = string.Join("", tt);

                values[i + 3] = id_0;
                values[i-1]=id_1;
			}


			return values;
			
		}
        public static int[] GetCurrentBatCodeFeed(string barcode, bool IsFirst, bool IsSecond, bool IsThird)
        {
            var pigeonCageId = barcode;
            int[] values = new int[8];
            if (string.IsNullOrWhiteSpace(pigeonCageId)) return values;

            var building = pigeonCageId[0];
            var arrange = pigeonCageId.Substring(1, 2);
            var group = pigeonCageId.Substring(3, 3);
            int.TryParse(arrange, out int arrangeInt);
            var isOdd = arrangeInt % 2 != 0;
            if (arrangeInt % 2 == 0) arrangeInt -= 1;
            var tt = pigeonCageId.ToArray();

            for (int i = 1; i <= 4; i++)
            {
                var number = i.ToString("D2");
                tt[6] = number[0];
                tt[7] = number[1];
                var firstLine = arrangeInt.ToString("D2");
                tt[1] = firstLine[0];
                tt[2] = firstLine[1];
                var id_0 =string.Join( "",tt);

                var secondLine = (arrangeInt + 1).ToString("D2");
                tt[1] = secondLine[0];
                tt[2] = secondLine[1];
                var id_1 = string.Join("", tt);
                //if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_0)) values[i - 1] = AppRuntime.TodayDosingSchedule.OKSchedues[id_0];
               // if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_1)) values[i + 3] = AppRuntime.TodayDosingSchedule.OKSchedues[id_1];
				if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_0)) values[i + 3] = AppRuntime.TodayDosingSchedule.OKSchedues[id_0];
				if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_1)) values[i -1] = AppRuntime.TodayDosingSchedule.OKSchedues[id_1];
			}
            GetFeedSceduleRate(ref values, IsFirst, IsSecond, IsThird);
            return values;
        }

        public static AgvFeedCupModel GetCurrentCups()
        {
            var res = GetPlcManager().GetAgvFeedCupModel();
            return res;
        }
        public static void ClearPlcCupRecord()
        {
            GetPlcManager().ClearAgvFeedCupModel();
        }


        public static bool InteractionPLCByQ(bool IsFirst, bool IsSecond, bool IsThird)
        {
            try
            {
                var pigeonCageId = GetPlcManager().GetBarCode();//A0100202-0000-0000-0000-000000000000
                if (string.IsNullOrWhiteSpace(pigeonCageId)) return false;
                if (TodayDosingSchedule.CagesRelations.ContainsKey(pigeonCageId))
                {
                    var building = pigeonCageId[0];
                    var arrange = pigeonCageId.Substring(1, 2);
                    var group = pigeonCageId.Substring(3, 3);
                    int.TryParse(arrange, out int arrangeInt);
                    var isOdd = arrangeInt % 2 != 0;
                    if (arrangeInt % 2 == 0) arrangeInt -= 1;
                    var tt = pigeonCageId.ToArray();
                    var newres = new int[8];
                    for (int i = 1; i <= 4; i++)
                    {
                        var number = i.ToString("D2");
                        tt[6] = number[0];
                        tt[7] = number[1];
                        var firstLine = arrangeInt.ToString("D2");
                        tt[1] = firstLine[0];
                        tt[2] = firstLine[1];
                        var id_0 = tt.ToString();

                        var secondLine = (arrangeInt + 1).ToString("D2");
                        tt[1] = firstLine[0];
                        tt[2] = firstLine[1];
                        var id_1 = tt.ToString();
                        //if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_0)) newres[i - 1] = AppRuntime.TodayDosingSchedule.OKSchedues[id_0];
                        //if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_1)) newres[i + 3] = AppRuntime.TodayDosingSchedule.OKSchedues[id_1];
						if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_0)) newres[i +3 ] = AppRuntime.TodayDosingSchedule.OKSchedues[id_0];
						if (AppRuntime.TodayDosingSchedule.OKSchedues.ContainsKey(id_1)) newres[i -1] = AppRuntime.TodayDosingSchedule.OKSchedues[id_1];

					}

                    GetFeedSceduleRate(ref newres, IsFirst, IsSecond, IsThird);
                    GetPlcManager().上位机喂料量下达(newres);

                    var msg = $"--------{pigeonCageId}____[{string.Join(",", newres)}]";
                    Logger_Info(msg);
                }
                return true;
            }
            catch (Exception ex)
            {
                Logger_Error(ex);
                return false;
            }
        }

        public static bool InteractionPLCByQ(int[] values, string barcode,int First_Second_Third=0)
        {
            try
            {
                

                GetPlcManager().上位机喂料量下达(values);

                 

                var msg = $"----{First_Second_Third}----{barcode}____[{string.Join(",", values)}]";
                Logger_Info(msg);

                return true;
            }
            catch (Exception ex)
            {
                Logger_Error(ex);
                return false;
            }

        }
        public static void Logger_Info(string msg)
        {
            if (IsLogger)
            {
                Logger.Value.Info(msg);
            }

        }
        public static void Logger_Error(string msg)
        {
            if (IsLogger)
            {
                Logger.Value.Error(msg);
            }

        }

        public static void Logger_Error(Exception ex)
        {
            if (IsLogger)
            {
                Logger.Value.Error(ex);
            }
        }
		public static bool IsNetworkAvailable()
		{
            return QNetWork.IsInternetAvailable();
			
		}
		public static int MajorityElement(int[] nums)
		{
			var count = 1;
			var major = nums[0];
			for (int i = 1; i < nums.Length; i++)
			{
				if (major == nums[i]) count++;
				else
				{
					count--;
					if (count == 0) major = nums[i + 1];
				}
			}
			return major;
		}


	}
}
